package ma.myschool.app.webapp.action;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import ma.myschool.app.Constants;
import ma.myschool.app.beans.EtatPaye;
import ma.myschool.app.model.Eleve;
import ma.myschool.app.model.ModePaiement;
import ma.myschool.app.model.MoisPaye;
import ma.myschool.app.model.Paiement;
import ma.myschool.app.model.TypePaiement;
import ma.myschool.app.service.EleveManager;
import ma.myschool.app.service.ModePaiementManager;
import ma.myschool.app.service.MoisPayeManager;
import ma.myschool.app.service.PaiementHistoryManager;
import ma.myschool.app.service.PaiementManager;
import ma.myschool.app.service.TypePaiementManager;

import org.primefaces.event.ToggleSelectEvent;
import org.primefaces.model.chart.CartesianChartModel;
import org.primefaces.model.chart.ChartSeries;
import org.primefaces.model.chart.PieChartModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component("paiementController")
@Scope("session")
public class PaiementController extends BasePage implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -1356484978768012435L;
	
	private PaiementManager paiementManager;
	private EleveManager eleveManager;
	private TypePaiementManager typePaiementManager;
	private ModePaiementManager modePaiementManager;
	private MoisPayeManager moisPayeManager;
	private PaiementHistoryManager paiementHistoryManager;

	private List<Paiement> paiements = new ArrayList<>();
	private List<String> moisSelecteds = new ArrayList<>();
	private List<String> moisPayes;
	
	private Long idEleve;
	private float montantAPaye;

	private Paiement paiement = new Paiement();
	private Eleve eleve = new Eleve();

	private List<Eleve> eleves = new ArrayList<>();
	private List<TypePaiement> typePaiements = new ArrayList<>();

	private Long id;
	private String query;

	@Autowired
	public void setPaiementManager(
			@Qualifier("paiementManager") PaiementManager paiementManager) {
		this.paiementManager = paiementManager;
	}

	@Autowired
	public void setPaiementHistoryManager(
			@Qualifier("paiementHistoryManager") PaiementHistoryManager paiementHistoryManager) {
		this.paiementHistoryManager = paiementHistoryManager;
	}

	@Autowired
	public void setModePaiementManager(@Qualifier("modePaiementManager") ModePaiementManager modePaiementManager) {
		this.modePaiementManager = modePaiementManager;
	}


	@Autowired
	public void setMoisPayeManager(@Qualifier("moisPayeManager") MoisPayeManager moisPayeManager) {
		this.moisPayeManager = moisPayeManager;
	}

	@Autowired
	public void setEleveManager(
			@Qualifier("eleveManager") EleveManager eleveManager) {
		this.eleveManager = eleveManager;
	}

	@Autowired
	public void setTypePaiementManager(
			@Qualifier("typePaiementManager") TypePaiementManager typePaiementManager) {
		this.typePaiementManager = typePaiementManager;
	}

	public PaiementController() {
		setSortColumn("id"); // sets the default sort column
	}

	public List<Paiement> getPaiements() {
		return sort(reloadPaiements());
	}

	public String cancel() {
		String result;
		if ("listEleve".equals(from))
			result = "listEleve";
		else if ("listPay".equals(from))
			result = "paiementList";
		else if("eleveDetail".equals(from))
			result = "eleveDetail";
		else
			result = "home";
		
		initForm();
		return result;
	}
	
	public String search() {
		return "success";
	}

	 public String detailEleve() {
        // Workaround for not being able to set the id using #{param.id} when using Spring-configured managed-beans
        id = getParameter("id") != null ? new Long(getParameter("id")) : null;
        
        // Comparison to zero (vs. null) is required with MyFaces 1.2.2, not with previous versions
        if (id != null && id != 0) {
            eleve = eleveManager.get(id);
        } else {
            eleve = new Eleve();
        }

        paiement.setEleve(eleve);
        
        return "eleveDetail";
    }
	 
	public String delete() {
		paiementManager.remove(paiement.getId());
		addMessage("paiement.deleted");

		return "list";
	}

	public String edit() {
		// Workaround for not being able to set the id using #{param.id} when
		// using Spring-configured managed-beans
		id = getParameter("id") != null ? new Long(getParameter("id")) : null;
		from = getParameter("from");
		// Comparison to zero (vs. null) is required with MyFaces 1.2.2, not
		// with previous versions
		if (id != null && id != 0) {
			paiement = paiementManager.get(id);
			if("inscription".equalsIgnoreCase(paiement.getMoisPaye() != null ? paiement.getMoisPaye().getLibelle() : ""))
				montantAPaye = paiement.getAnneeScolaire().getFraisInscription();
			else
				montantAPaye = paiement.getEleve().getPaiementMensuel() + paiement.getEleve().getPaiementTransport();	
		} else {
			idEleve = getParameter("idEleve") != null ? new Long(getParameter("idEleve")) : null;

			eleve = eleveManager.get(idEleve);
			eleve = eleve != null ? eleve : new Eleve();
			paiement = new Paiement();
			paiement.setEleve(eleve);
			moisSelecteds = new ArrayList<>();
		}

        return "editPay";
	}
	
	public String viewPaiementForm(){
		initForm();

		from = getParameter("from");
		if("eleveDetail".equals(from)){
			idEleve = getParameter("idEleve") != null ? new Long(getParameter("idEleve")) : null;
			idEleve = new Long(idEleve);
	
			eleve = eleveManager.get(idEleve);
			paiement = new Paiement();
			paiement.setEleve(eleve);
			moisSelecteds = new ArrayList<>();
		}
		
		return "paiementForm";
	}
	
	public String viewPaiementList(){
		initForm();
		from = getParameter("from");
		return "paiementList";
	}
	
	public String viewPaiementEtat(){
		initForm();
		from = getParameter("from");
		return "paiementEtat";
	}

	public String save() {
		
		boolean isNew = (paiement.getId() == null || paiement.getId() == 0);
		anneeScolaire = appController.getAnneeScolaire();
		
		if(!validatePayement(isNew))
			return "edit";
		
		boolean isJustifie = paiement.isAvanceJustifie();
		TypePaiement typePaiement = new TypePaiement();
		
		paiement.setAnneeScolaire(anneeScolaire);
		paiement.setAvanceJustifie(false);
		
		if(isNew){
			float avance = paiement.getAvance();
			float montantMensuel = paiement.getEleve().getPaiementMensuel() + paiement.getEleve().getPaiementTransport();
			float fraisInscription = appController.getAnneeScolaire().getFraisInscription();
			if(checkInscriptionChecked()){
				typePaiement.setId(Constants.TYPE_PAIEMENT_INSCRIPTION_ID);
				if(avance - fraisInscription >= 0){
					paiement.setAvance(fraisInscription);
					paiement.setReste(0);
					avance -= fraisInscription;
				}else{
					paiement.setAvance(avance);
					paiement.setReste(fraisInscription - avance);
					paiement.setAvanceJustifie(isJustifie);
					avance = 0;
				}
				paiement.setMoisPaye(moisPayeManager.getMoisPayeByLibelle(Constants.INSCRIPTION));

				paiement.setTypePaiement(typePaiement);
				paiement = paiementManager.save(paiement);
				
				moisSelecteds.remove(paiement.getMoisPaye().getLibelle());
			}
			
			if(avance > 0){
				for (String libelle : getMoisSelecteds()) {
					typePaiement.setId(Constants.TYPE_PAIEMENT_MENSUEL_ID);
					if((avance - montantMensuel )>= 0){
						paiement.setAvance(montantMensuel);
						paiement.setReste(0);
						avance -=  montantMensuel;
					}else{
						paiement.setAvance(avance);
						paiement.setAvanceJustifie(isJustifie);
						if(isJustifie)
							paiement.setReste(0);
						else
							paiement.setReste(montantMensuel - avance);
					}
					
					paiement.setId(null);
					paiement.setTypePaiement(typePaiement);
					paiement.setMoisPaye(moisPayeManager.getMoisPayeByLibelle(libelle));
					paiementManager.save(paiement);
				}
			}
		}else{
			if(isJustifie)
				paiement.setReste(0);
			else{
				if("inscription".equalsIgnoreCase(paiement.getMoisPaye() != null ? paiement.getMoisPaye().getLibelle() : ""))
					paiement.setReste(paiement.getAnneeScolaire().getFraisInscription() - paiement.getAvance());
				else
					paiement.setReste((paiement.getEleve().getPaiementMensuel() + paiement.getEleve().getPaiementTransport()) - paiement.getAvance());
			}
			paiement.setAvanceJustifie(isJustifie);
			paiement = paiementManager.save(paiement);
		}
		
		String key = (isNew) ? "paiement.added" : "paiement.updated";
		addMessage(key);

		String result;
		
		if ("listPay".equals(from)
				|| (getMoisAPayes() == null || getMoisAPayes().isEmpty()))
			result = "paiementList";
		else
			result = "edit";

		//init form to add a new paiement
		initForm();
				
		return result;
	}

	private List<Paiement> reloadPaiements() {
		paiements = paiementManager.loadPaiementsByEleve(eleve != null ? eleve.getId() : null, appController.getAnneeScolaire());
		paiements = paiements != null ? paiements : new ArrayList<Paiement>();
		return paiements;
	}

	private boolean validatePayement(boolean isNew) {
		boolean result = true;
		
		if(isNew && (moisSelecteds == null || moisSelecteds.isEmpty())){
			addError("errors.moisSelected.empty");
			result = false;
		}
		
		if(isNew && (anneeScolaire == null || anneeScolaire.getId() == null  || anneeScolaire.getId() <= 0)){
			addError("errors.anneeScolaire");
			result = false;
		}
		
		if(eleve == null || eleve.getId() == null || eleve.getId() <= 0){
			addError("errors.eleve");
			result = false;
		}
		
//		if(paiement.getAvance() != montantAPaye && !paiement.isAvanceJustifie()){
//			addError("errors.avance.justifie");
//			result = false;
//		}
		
		return result;
	}

	private boolean checkInscriptionChecked() {
		boolean result = false;
		MoisPaye moisPaye = null;
		for (String libelle : getMoisSelecteds()) {
			moisPaye = moisPayeManager.getMoisPayeByLibelle(libelle);
			if("inscription".equalsIgnoreCase(moisPaye != null ? moisPaye.getLibelle() : "")){
				result = true;
				break;
			}
		}
		
		return result;
	}
	
	private boolean checkInscriptionExist(MoisPaye moisPaye) {
		boolean result = false;
		if("inscription".equalsIgnoreCase(moisPaye.getLibelle())){
			result = true;
		}
		
		return result;
	}

	private void initForm() {
		idEleve = null;
		paiement = new Paiement();
		paiement.setEleve(eleve);
		moisSelecteds = new ArrayList<>();
		moisPayes = null;
		montantAPaye = 0;
		from = null;
	}

	public List<Eleve> getEleves() {
		eleves = eleveManager.getAll();
		if (eleves == null)
			return new ArrayList<>();
		return sort(eleves, "numeroInscription", true, false);
	}

	public List<TypePaiement> getTypePaiements() {
		typePaiements = typePaiementManager.getAll();
		if (typePaiements == null)
			return new ArrayList<>();
		return sort(typePaiements, "libelle", true, false);
	}
	
	public List<TypePaiement> getModePaiements() {
		List<ModePaiement> modePaiements = modePaiementManager.getAll();
		if (modePaiements == null)
			return new ArrayList<>();
		return sort(modePaiements, "id", true, false);
	}

//	public void handleModePaiementChange() {
//		if (paiement.getModePaiement() != null && paiement.getModePaiement().getId() != null) {
//			ModePaiement modePaiement = modePaiementManager.get(paiement.getModePaiement().getId());
//			if ("Chèque".equalsIgnoreCase(modePaiement != null ? modePaiement.getLibelle() : null))
//				showNumeroCheque = true;
//			else
//				showNumeroCheque = false;
//		}
//	}
	
	/**
	 * reste = (monatant mensuel * nbr du mois) - avance 
	 * si le result < 0 le reste sera 0
	 */
	public void handleAvanceChange(){
		boolean isNew = (paiement.getId() == null || paiement.getId() == 0);
		if(isNew){
			if(getMoisSelecteds() != null && !getMoisSelecteds().isEmpty()){
				float montantMensuel = paiement.getEleve().getPaiementMensuel() + paiement.getEleve().getPaiementTransport();
				float fraisInscription = checkInscriptionChecked() ? appController.getAnneeScolaire().getFraisInscription() : 0;
				int nbrMois =checkInscriptionChecked() ? getMoisSelecteds().size() - 1 : getMoisSelecteds().size();
				float result = ((nbrMois * montantMensuel) + fraisInscription) - paiement.getAvance();
				paiement.setReste(result >= 0 ? result : 0);
				
				//update montant a paye
				montantAPaye = (nbrMois * montantMensuel) + fraisInscription;
			}else{
				paiement.setReste(0);
				montantAPaye = 0;
			}
		}else{
			if("inscription".equalsIgnoreCase(paiement.getMoisPaye() != null ? paiement.getMoisPaye().getLibelle() : ""))
				paiement.setReste(paiement.getAnneeScolaire().getFraisInscription() - paiement.getAvance()); 
			else
				paiement.setReste((paiement.getEleve().getPaiementMensuel() + paiement.getEleve().getPaiementTransport()) - paiement.getAvance()); 
		}
	}
	
	public void handleToggleMoisSelected(ToggleSelectEvent toggle){
		if(toggle.isSelected()){
			montantAPaye = 0;
			float montantMensuel = paiement.getEleve().getPaiementMensuel() + paiement.getEleve().getPaiementTransport();
			for (String moisPaye : getMoisAPayes()) {
				if("inscription".equalsIgnoreCase(moisPaye)){
					montantAPaye += appController.getAnneeScolaire().getFraisInscription();
				}else{
					montantAPaye += montantMensuel;
				}
			}
			
			paiement.setReste(montantAPaye - paiement.getAvance());
		}else{
			paiement.setReste(0);
			montantAPaye = 0;
		}
	}
	
	public void handleNumeroInscriptionChange(){
		eleve = eleveManager.loadEleveByNumeroInscription(eleve.getNumeroInscription());
		if(eleve == null){
			eleve = new Eleve();
			addError("errors.numeroInscription.found");
		}
		
		paiement.setEleve(eleve);
	}
	
//	 public void handleTabChange(TabChangeEvent event) {
//	       String tabId = event.getTab().getId();
//	       if("listPaiement".equalsIgnoreCase(tabId)){
//	        	paiements = paiementManager.loadPaiementsByEleve(eleve != null ? eleve.getId() : null);
//	    		paiements = paiements != null ? paiements : new ArrayList<Paiement>();
//	    		initForm();
//	        }else
//	        	initForm();
//	        	
//	  
//	    }  

	public boolean isShowNumeroCheque() {
		if (paiement.getModePaiement() != null && paiement.getModePaiement().getId() != null) {
			ModePaiement modePaiement = modePaiementManager.get(paiement.getModePaiement().getId());
			if ("Chèque".equalsIgnoreCase(modePaiement != null ? modePaiement.getLibelle() : null))
				return true;
			else
				return false;
		}
		
		return false;
	}

	public Long getIdEleve() {
		return idEleve;
	}

	public void setIdEleve(Long idEleve) {
		this.idEleve = idEleve;
	}

	public void setQuery(String query) {
		this.query = query;
	}

	public String getQuery() {
		return query;
	}
	
	public boolean isEdit() {
		boolean isNew = (paiement.getId() == null || paiement.getId() == 0);
		return !isNew;
	}

	public Paiement getPaiement() {
		if(paiement != null)
			paiement.setPaiementHistory(paiementHistoryManager.listPaiementHistoryByPay(paiement.getId()));
		
		return paiement;
	}

	public void setPaiement(Paiement paiement) {
		this.paiement = paiement;
	}

	public Eleve getEleve() {
		return eleve;
	}

	public void setEleve(Eleve eleve) {
		this.eleve = eleve;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public List<String> getMoisSelecteds() {
		return moisSelecteds;
	}

	public void setMoisSelecteds(List<String> moisSelecteds) {
		this.moisSelecteds = moisSelecteds;
	}
	
	public float getMontantAPaye() {
		return montantAPaye;
	}

	public List<String> getMoisAPayes() {
		moisPayes = new ArrayList<>();
		
		List<MoisPaye> allMois = moisPayeManager.getAll();
		for (MoisPaye moisPaye : allMois) {
			if(!checkMoisAlreadyPaid(moisPaye))
				moisPayes.add(moisPaye.getLibelle());
		}
		
		return moisPayes;
	}
	
	public List<EtatPaye> getEtatPayes(){
		List<EtatPaye> result = new ArrayList<>();
		List<MoisPaye> allMois = moisPayeManager.getAll();
		if(allMois != null){
			for (int i = 0; i < allMois.size(); i++) {
				result.add(retrieveEtatPaye(allMois.get(i)));
			}
		}
		
		return result;
		
	}

	public PieChartModel getPieModelRecettes() {
		PieChartModel pieModel = new PieChartModel();
		Number totalPaiement = paiementManager.sumAvancePaiements(appController.getAnneeScolaire());
		pieModel.set(getText("recette.pie.encaissement") + " : " + totalPaiement.toString(), totalPaiement);
		//total reste = total annuel - total avance paiement
		Number totalReste = (paiementManager.sumAllPaiementsPrevu().doubleValue() * 10)
								+ paiementManager.sumAllRestePaiement(appController.getAnneeScolaire()).doubleValue()
									+ (eleveManager.getSizeAll().doubleValue() * appController.getAnneeScolaire().getFraisInscription());
		totalReste = totalReste.doubleValue() - totalPaiement.doubleValue();
		pieModel.set(getText("recette.pie.encaissement.reste") + " : " + totalReste.toString(), totalReste);
        return pieModel;  
    }
	
	public CartesianChartModel getCategoryModelRecettes() { 
		CartesianChartModel categoryModel = new CartesianChartModel();  
  
        ChartSeries encaissement = new ChartSeries(); 
        encaissement.setLabel(getText("recette.etat.paiement.mensuel.effectue"));  
        List<MoisPaye> moisPayes = sort(moisPayeManager.getAll(), "id", true, false);
        
        for (MoisPaye moisPaye : moisPayes) {
        	encaissement.set(moisPaye.getLibelle(), paiementManager.sumAvancePaimentParMois(moisPaye, appController.getAnneeScolaire()));
		}
  
        ChartSeries totalPrevu = new ChartSeries();  
        totalPrevu.setLabel(getText("recette.etat.paiement.mensuel.prevus"));  
        
        for (MoisPaye moisPaye : moisPayes) {
        	if(!checkInscriptionExist(moisPaye))
        		totalPrevu.set(moisPaye.getLibelle(), paiementManager.sumAllPaiementsPrevu().doubleValue());
        	else
        		totalPrevu.set(moisPaye.getLibelle(), eleveManager.getSizeAll().doubleValue() * appController.getAnneeScolaire().getFraisInscription());
		}
        
        ChartSeries totalReste = new ChartSeries();  
        totalReste.setLabel(getText("recette.etat.paiement.mensuel.reste"));  
  
        Number tReste; 
        		
        for (MoisPaye moisPaye : moisPayes) {
        	if(!checkInscriptionExist(moisPaye)){
	        	tReste = paiementManager.sumAllPaiementsPrevu().doubleValue() - paiementManager.sumAvancePaimentParMois(moisPaye, appController.getAnneeScolaire()).doubleValue();
	        	totalReste.set(moisPaye.getLibelle(), tReste);
        	}else{
        		tReste = (eleveManager.getSizeAll().doubleValue() * appController.getAnneeScolaire().getFraisInscription()) - paiementManager.sumAvancePaimentParMois(moisPaye, appController.getAnneeScolaire()).doubleValue();
	        	totalReste.set(moisPaye.getLibelle(), tReste);
        	}
		}
  
        categoryModel.addSeries(totalPrevu);
        categoryModel.addSeries(encaissement);
        categoryModel.addSeries(totalReste);
        return categoryModel;  
    }
	
	private EtatPaye retrieveEtatPaye(MoisPaye moisPaye) {
		EtatPaye etatPaye = null;
		paiements = reloadPaiements();
		if(paiements != null){
			for (Paiement paiement : paiements) {
				if(moisPaye.equals(paiement.getMoisPaye())){
					etatPaye = new EtatPaye(moisPaye.getLibelle(), true, paiement);
					break;
				}
					
			}
		}
		 if(etatPaye == null)
			 etatPaye = new EtatPaye(moisPaye.getLibelle(), false, null);
		
		 return etatPaye;
	}

	private boolean checkMoisAlreadyPaid(MoisPaye moisPaye) {
		boolean result = false;
		if(eleve != null){
			List<Paiement> moisAlreadyPaid = paiementManager.loadPaiementsByEleve(eleve.getId(), appController.getAnneeScolaire());
			for (Paiement paiement : moisAlreadyPaid != null ? moisAlreadyPaid : new ArrayList<Paiement>()) {
				if(paiement.getMoisPaye().getLibelle().equals(moisPaye.getLibelle()))
					result = true;
			}
		}
		
		return result;
	}
}